

#include <regex>
#include <iostream>
#include "core.h"
#include "stralgo_s.h"
#include "relation.h"
#include "science.h"

using std::cout;
using std::cin;
using std::endl;
using std::regex;
using std::smatch;

string core(const string &str)
{
	smatch result, ans; //result used outside, ans used inside
	string temp, p;//temp used to calculate every simple expression, p used to modify every pattern inside
	regex reg; //regex used inside
	string product, front, back; //product stores the every simple result, 
	//front represent the expression before the found expression
	//back represent the expression after the found expression

	string expression(str);
	string pattern = "(\\()([-])([0-9]+)([.][0-9]+)?(\\))";  //find(-15)or(-15.02),and transform it into -15 or -15.02
	regex r(pattern);
	string format = "0$3$4";

	expression = regex_replace(expression, r, format);
	//cout << expression << endl;

	pattern = "(\\()([0-9]+)([.][0-9]+)?(\\))";  //find(15)or(15.02),and transform it to 15 or 15.02
	r.assign(pattern);
	format = "$2$3";

	expression = regex_replace(expression, r, format);
	//cout << expression << endl;

	pattern = "(s)([0-9]+)([.][0-9]+)?";  //find s(x), and calculate it as sin(x)
	r.assign(pattern);
	while (regex_search(expression, result, r))
	{
		temp = result.str(2) + result.str(3);
		product = sin(temp);
		expression = result.prefix().str() + product + result.suffix().str();
	}


	pattern = "(c)([0-9]+)([.][0-9]+)?";  //find c(x), and calculate it as cos(x)
	r.assign(pattern);
	while (regex_search(expression, result, r))
	{
		temp = result.str(2) + result.str(3);
		product = cos(temp);
		expression = result.prefix().str() + product + result.suffix().str();
	}


	pattern = "(e)([0-9]+)([.][0-9]+)?";  //find e(x), and calculate it as Exp(x)
	r.assign(pattern);
	while (regex_search(expression, result, r))
	{
		temp = result.str(2) + result.str(3);
		product = Exp(temp);
		expression = result.prefix().str() + product + result.suffix().str();
	}


	pattern = "([0-9]+)([.][0-9]+)?(!)";  //find (x)!, and calculate it as factorial(x)
	r.assign(pattern);
	while (regex_search(expression, result, r))
	{
		if (result.str(2) != "")
		{
			cerr << "invalid expression of " << result.str() << "!";
			exit(1);
		}
		temp = result.str(1);
		product = factorial(temp);
		expression = result.prefix().str() + product + result.suffix().str();
	}


	pattern = "(\\()([0-9]+)([.][0-9]+)?([-+/*%#^]([0-9]+)([.][0-9]+)?)+(\\))"; //find the compound expression in the ( )

	r.assign(pattern);
	
	while (regex_search(expression, result, r))//inside start
	{
		temp = result.str();

		p = "([0-9]+)([.][0-9]+)?([#^])([0-9]+)([.][0-9]+)?";
		reg.assign(p);
		while (regex_search(temp, ans, reg))
		{
			if (ans.str(5) != "")
			{
				throw "doesn't support this root expression";
			}
			string first = ans.str(1) + ans.str(2);
			string second = ans.str(4);
			string sign = ans.str(3);
			if (sign == "^")
			{
				product = Pow(first, second);
			}
			else
			{
				product = Root(first, second);
			}
			
			temp = ans.prefix().str() + product + ans.suffix().str();
			//cout << temp << endl;
		}
		
		/*p = "([0-9]+)([.][0-9]+)?(\\^)([0-9]+)([.][0-9]+)?";
		reg.assign(p);
		while (regex_search(temp, ans, reg))
		{
			if (ans.str(5) != "")
			{
				throw "doesn't support this root expression";
			}
			string first = ans.str(1) + ans.str(2);
			string second = ans.str(4);
			product = Pow(first, second);
			temp = ans.prefix().str() + product + ans.suffix().str();
			cout << temp << endl;
		}*/

		p = "([0-9]+)([.][0-9]+)?([/*%])([0-9]+)([.][0-9]+)?";  //find the / %or* expression
		reg.assign(p);
		while (regex_search(temp, ans, reg))
		{
			string first = ans.str(1) + ans.str(2);
			string second = ans.str(4) + ans.str(5);
			string sign = ans.str(3);
			if (Equal(sign, "*"))
			{
				product = Multiply_s(first, second);
			}
			else if (Equal(sign, "/"))
			{
				product = Divide_s(first, second);
			}
			else
			{
				product = first % second;
			}
			temp = ans.prefix().str() + product + ans.suffix().str();
		}



		p = "([0-9]+)([.][0-9]+)?([-+])([0-9]+)([.][0-9]+)?"; //find the +or- expression
		reg.assign(p);

		while (regex_search(temp, ans, reg))
		{
			string first = ans.str(1) + ans.str(2);
			string second = ans.str(4) + ans.str(5);
			if (ans.str(3) == "+")
			{
				product = Plus_s(first, second);
			}
			else
			{
				product = Reduce_s(first, second);
			}
			temp = ans.prefix().str() + product + ans.suffix().str();
		}

		expression = result.prefix().str() + string(temp.begin() + 1, temp.end() - 1) + result.suffix().str();
	}//inside end



	pattern = "(\\()([0-9]+)([.][0-9]+)?(\\))";  //find(15)or(15.02),and replace it to 15 or 15.02
	r.assign(pattern);
	format = "$2$3";
	expression = regex_replace(expression, r, format);


	pattern = "([0-9]+)([.][0-9]+)?([#^])([0-9]+)([.][0-9]+)?";
	r.assign(pattern);
	while (regex_search(expression, result, r))
	{
		if (result.str(5) != "")
		{
			throw "doesn't support this root expression";
		}

		string first = result.str(1) + result.str(2);
		string second = result.str(4);
		string sign = result.str(3);

		if (sign == "^")
		{
			product = Pow(first, second);
		}
		else
		{
			product = Root(first, second);
		}
		expression = result.prefix().str() + product + result.suffix().str();
	}


	//no longer ( ) here
	pattern = "([0-9]+)([.][0-9]+)?([/*%])([0-9]+)([.][0-9]+)?";
	r.assign(pattern);
	while (regex_search(expression, result, r))
	{

		string first = result.str(1) + result.str(2);
		string second = result.str(4) + result.str(5);
		string sign = result.str(3);
		if (Equal(sign, "*"))
		{
			product = Multiply_s(first, second);
		}
		else if (Equal(sign, "/"))
		{
			product = Divide_s(first, second);
		}
		else
		{
			product = first % second;
		}
		expression = result.prefix().str() + product + result.suffix().str();
	}

	pattern = "([0-9]+)([.][0-9]+)?([-+])([0-9]+)([.][0-9]+)?";
	r.assign(pattern);
	while (regex_search(expression, result, r))
	{
		string first = result.str(1) + result.str(2);
		string second = result.str(4) + result.str(5);
		if (result.str(3) == "+")
		{
			product = Plus_s(first, second);
		}
		else
		{
			product = Reduce_s(first, second);
		}
		
		expression = result.prefix().str() + product + result.suffix().str();
	}

	//cout << expression << endl;
	pattern = "^([0-9]+)([.][0-9]+)?$";
	r.assign(pattern);
	if (regex_search(expression,result,r))
	{
	
		if ((expression.length() != 1) &&
			(expression[0] == '0') &&
			((expression[1] != '.') || (expression[1] == '0')))
		{
			expression[0] = '-';
		}


		if (result.str(2).length() >= 15) 
		{
			string origin = result.str(2);
			//cout << origin << endl;
			string front = result.str(1);
			string back = origin.substr(0, 13);
			expression = front + back;
			if (origin[13] >= '5')
			{
				expression = Plus_s(expression, "0.000000000001");
			}
			
		}


		return expression;
	}
	else
	{
		return "wrong expression";
	}

}


